%%%-------------------------------------------------------------------
%%% @author mirahs(2892727493@qq.com)
%%% @doc
%%%     网络 websocket
%%% @end
%%%-------------------------------------------------------------------
-module(net_http_websocket_handler).

-export([init/2]).

-export([websocket_init/1, websocket_handle/2, websocket_info/2, terminate/3]).

-include("common.hrl").
-include("net.hrl").
-include("env.hrl").


%%%===================================================================
%%% cowboy websocket implementation
%%%===================================================================

init(Req, _Opts) ->
    Module = env_mgr:get(?ENV_NET_PROTOCOL_HANDLER),
    {Ip, Port} = cowboy_req:peer(Req),

    State = #net_conn{is_cowboy = true, module = Module, ip = util_type:ip_to_bitstring(Ip), port = Port, read_head = true},
    % 30 秒超时关闭连接
    Params = #{idle_timeout => 30000},

    {cowboy_websocket, Req, State, Params}.


websocket_init(State) ->
    erlang:process_flag(trap_exit, true),
    {ok, State}.


websocket_handle({text, ?NET_CLIENT_GAME}, State = #net_conn{read_head = true}) ->
    {ok, State#net_conn{type = game, read_head = false, read_cont = true}};
websocket_handle({text, ?NET_CLIENT_TESTER}, State = #net_conn{read_head = true}) ->
    {ok, State#net_conn{type = tester, read_head = false, read_cont = true}};
websocket_handle({text, _Data}, State = #net_conn{read_head = true}) ->
    ?ERR("错误头数据:~w", [_Data]),
    {stop, State};

websocket_handle({binary, Bin}, State = #net_conn{read_head = false, bins = Bins}) ->
    do_packet(State#net_conn{bins = lists:reverse([Bin | Bins])});

websocket_handle(Data, State) ->
    ?ERR("未知消息 :~p", [Data]),
    {ok, State}.


websocket_info(read_next, State) ->
    read_next(State);

websocket_info({send, Bin}, State = #net_conn{send_count = SendCount}) ->
    {[{binary, Bin}], State#net_conn{send_count = SendCount + 1}};

websocket_info({send_filter, BinTmp}, State = #net_conn{object_id = Oid, send_count = SendCount}) ->
    case filter_self(BinTmp, [], Oid) of
        [] ->
            {ok, State};
        Bin ->
            {[{binary, Bin}], State#net_conn{send_count = SendCount + 1}}
    end;

websocket_info(Info, State) ->
    ?ERR("未知消息 :~p", [Info]),
    {ok, State}.


terminate(_Reason, _Req, #net_conn{module = Module, account = _Account, object = Object, object_pid = OPid}) ->
    catch Module:on_close(Object, OPid),
    ?DEBUG("帐号[~s]的连接进程已退出", [_Account]),
    ok.


%%%===================================================================
%%% Internal functions
%%%===================================================================

read_next(State) ->
    {ok, State#net_conn{read_cont = true}}.

do_packet(State = #net_conn{read_cont = true, module = Module, bins = [Bin | Bins]}) ->
    HeadSize = Module:head_size(),
    case Bin of
        <<HeadBin:HeadSize/binary, BodyBin/binary>> ->
            case Module:on_packet(HeadBin, BodyBin, State#net_conn{read_cont = false, bins = Bins}) of
                {ok, StateNew} ->
                    {ok, StateNew};
                {next, StateNew} ->
                    read_next(StateNew);
                stop ->
                    {stop, State}
            end;
        _ ->
            ?ERR("错误数据:~w", [Bin]),
            {stop, State}
    end;
do_packet(State) ->
    {ok, State}.


filter_self([], Acc, _Oid) ->
    Acc;
filter_self([H | T], Acc, Oid) when erlang:is_list(H) ->
    filter_self(T, filter_self(H, Acc, Oid), Oid);
filter_self([{Oid, _} | T], Acc, Oid) ->
    filter_self(T, Acc, Oid);
filter_self([{_, Bin} | T], Acc, Oid) ->
    filter_self(T, [Bin | Acc], Oid);
filter_self([Bin | T], Acc, Oid) ->
    filter_self(T, [Bin | Acc], Oid).
